/*
 *  Copyright (c) Skrumtious
 */
package com.skrumtious.backend.persistence;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * The scrum listings
 * 
 * @author Tony
 *
 */
public class SkrumList extends PersistenceObject implements Serializable {
	
	/**
	 * SUID
	 */
	private static final long serialVersionUID = -5393851133457271772L;
	
	/**
	 * Items
	 */
	private List<SkrumItem> items;
	
	private Comparator<SkrumItem> descendingSorter = new Comparator<SkrumItem>() {
		
		@Override
		public int compare(SkrumItem o1, SkrumItem o2) {
			return o2.getOrder() - o1.getOrder();
		}
	};
	
	private Comparator<SkrumItem> ascendingSorter = new Comparator<SkrumItem>() {
		
		@Override
		public int compare(SkrumItem o1, SkrumItem o2) {
			return o1.getOrder() - o2.getOrder();
		}
	};
	
	/**
	 * @param items
	 */
	public SkrumList(List<SkrumItem> items) {
		super();
		this.items = items;
	}

	/**
	 */
	public SkrumList() {	
		this(new ArrayList<SkrumItem>());
	}
	
	/**
	 * @return the items
	 */
	public List<SkrumItem> getItems() {
		Collections.sort(this.items, this.descendingSorter);
		return items;
	}
	
	/**
	 * @param items the items to set
	 */
	public void setItems(List<SkrumItem> items) {
		this.items = items;
	}
	
	/**
	 * Adds a skrum item.
	 * 
	 * @param item
	 */
	public void addSkrumItem(SkrumItem item) {
		this.items.add(item);
		item.setOrder(this.items.size() - 1);
	}
	
	private void checkIndex(List<SkrumItem> items, int index) {
		if ( index < 0 || index >= items.size() ) {
			throw new IllegalArgumentException("Invalid itemId: " + index + " for " + this.getKey());
		}
	}
	
	/**
	 * Removes a {@link SkrumItem}
	 * @param itemId
	 * @return the item removed
	 */
	public SkrumItem removeSkrumItem(int itemId) {
		checkIndex(items, itemId);
		
		SkrumItem result = this.items.remove(itemId);
		
		updateIndexes(this.items, itemId);
		return result;
	}
	
	/**
	 * Removes a {@link SkrumItem} and shifts
	 * all order numbers.
	 * 
	 * @param item
	 */
	public void removeSkrumItem(SkrumItem item) {
		int idx = this.items.indexOf(item);
		if ( idx > -1 ) {
			this.items.remove(idx);
			
			updateIndexes(this.items, idx);
		}
	}
	
	/**
	 * Update the indexes.
	 * 
	 * @param items
	 * @param idx
	 */
	private void updateIndexes(List<SkrumItem> items, int idx) {
		/* Update the order */
		for(int i = idx; i < items.size(); i++ ) {
			SkrumItem sItem = items.get(i);
			sItem.setOrder(i);
		}
	}
	
	/**
	 * Swap positions
	 * @param a
	 * @param b
	 */
	public void swap(int a, int b) {
		checkIndex(items, a);
		checkIndex(items, b);
		
		SkrumItem aItem = this.items.get(a);
		SkrumItem bItem = this.items.get(b);
		
		this.items.set(b, aItem);
		this.items.set(a, bItem);
		
		bItem.setOrder(a);
		aItem.setOrder(b);		
	}
	
	/**
	 * Reorders based on the supplied ordering.
	 * 
	 * @param order
	 */
	public void reorder(int[] order) {
		if ( order == null ) {
			throw new IllegalArgumentException("The reorder list can not be null");
		}
		
		List<SkrumItem> skrumItems = getItems(); /* Sorts the items */
//		Collections.sort(skrumItems, this.ascendingSorter);
		
		if ( order.length != skrumItems.size()) {
			throw new IllegalArgumentException
				("The supplied reorder isn't the same dimensions for the stored list: " + skrumItems.size() + " vs. " + order.length);
		}
		
		
		/** First check all indexes are good, before
		 * we proceed to change the indexes
		 */
		boolean[] usedOrder = new boolean[order.length];
		for(int i = 0; i < order.length; i++) {
			int newOrder = order[i];
			checkIndex(skrumItems, newOrder);
			if ( skrumItems.get(i) == null ) {
				throw new IllegalStateException("The supplied SkrumItem is null at index: " + i);
			}
			
			usedOrder[newOrder] = true;
		}
		
		/* Verify all indexes are accounted for */
		for(int i = 0; i < usedOrder.length; i++) {
			if ( ! usedOrder[i]) {
				throw new IllegalArgumentException("No valid desitination for SkrumItem at: " + i + " with newOrder: " + order[i]);
			}
		}
		
		
		/* Now finally apply the changes */
		for(int i = 0; i < order.length; i++) {
			int newOrder = order[i];
			skrumItems.get(i).setOrder(newOrder);
		}
	}
}
